/*
 * COPYRIGHT:         LGPL, see LGPL.txt in the top level directory
 * PROJECT:           ReactOS Win32 subsystem
 * PURPOSE:           FLOATOBJ floating point emulation functions for x86
 * FILE:              win32ss/gdi/eng/i386/floatobj.S
 * PROGRAMMER:        Timo Kreuzer
 */

#include <asm.inc>

.code

/*******************************************************************************
 * IEEE 754-1985 single precision floating point
 *
 *    | 31 | 30...23  | 22...0   |
 *    |sign| exponent | fraction |
 *
 *  mantissa = 1 + (fraction / 2^23)
 *  f = (-1)^sign * mantissa * 2 ^ (exponent - bias)
 *  bias = 127
 *
 *******************************************************************************
 * win32k x86 floating point emulation
 *
 * struct _EFLOAT
 = {
 *    LONG lMant;
 *    LONG lExp;
 * };
 *
 * f = (lMant / 0x40000000) * 2 ^ (lExp - 2)
 *   = lMant * 2 ^ (lExp - 32)
 *
 *******************************************************************************
 * Optimization notes:
 *
 * - shld is slow (4 cycles) and not pairable, mov + shl is faster
 * - esp is used, because it's available earlier
 * - bsr is very slow on old cpus (up to 72 cycles on a p1) while being much
 *   faster on modern cpus (2-11 cycles). Workarounds using branch trees or
 *   table lookups are of no use nowadays.
 *******************************************************************************
 * Compatibility notes:
 * - There are issues with very large size values near integer overflow.
 *   Floating point values are behaving different there. This behavior isn't
 *   simulated yet. Difference is < 10^-5 %
 * - The result of a multiplication can differ from Windows result in the
 *   least significant bit, that is a difference of 1 / 2^30 or ~10^-9
 *******************************************************************************
 * Implementation status:
 *
 * FLOATOBJ_SetFloat - implemented, tested
 * FLOATOBJ_SetLong - implemented, tested
 * FLOATOBJ_GetFloat - implemented, tested
 * FLOATOBJ_GetLong - implemented, tested
 * FLOATOBJ_Equal - implemented, tested
 * FLOATOBJ_EqualLong - implemented
 * FLOATOBJ_GreaterThan - implemented
 * FLOATOBJ_GreaterThanLong - wrapper
 * FLOATOBJ_LessThan - implemented
 * FLOATOBJ_LessThanLong - wrapper
 * FLOATOBJ_Neg - implemented
 * FLOATOBJ_Mul - implemented, tested, optimized
 * FLOATOBJ_MulFloat - wrapper
 * FLOATOBJ_MulLong - wrapper, could really need optimization
 * FLOATOBJ_Div - implemented
 * FLOATOBJ_DivFloat - wrapper
 * FLOATOBJ_DivLong - wrapper
 * FLOATOBJ_Add - implemented, tested
 * FLOATOBJ_AddFloat - wrapper
 * FLOATOBJ_AddLong - wrapper
 * FLOATOBJ_Sub - implemented, tested
 * FLOATOBJ_SubFloat - wrapper
 * FLOATOBJ_SubLong - wrapper
 */

#define lMant 0
#define lExp 4

#define PARAM1 8
#define PARAM2 12

/** Globals **/
/* extern const FLOATOBJ gef0; */
PUBLIC _gef0
_gef0:
    .long 0, 0

/* extern const FLOATOBJ gef1; */
PUBLIC _gef1
_gef1:
    .long HEX(40000000), HEX(00000002)

/* extern const FLOATOBJ gef16; */
PUBLIC _gef16
_gef16:
    .long HEX(40000000), HEX(00000006)

/******************************************************************************
 * VOID
 * APIENTRY
 * FLOATOBJ_SetFloat(IN OUT PFLOATOBJ pf, IN FLOATL f);
 */
_FLOATOBJ_SetFloat@8:
PUBLIC _FLOATOBJ_SetFloat@8
	push ebp
	mov ebp, esp

	mov ecx, [esp + PARAM2]		/* Load the float into ecx */
	mov eax, ecx				/* Copy float to eax for later */

	test ecx, HEX(7f800000)		/* Check for zero exponent - 0 or denormal */
	jz SetFloat0				/* If it's all zero, ... */

	shl ecx, 7					/* Put the bits for the mantissa in place */

	cdq							/* Fill edx with the sign from the FLOATL in eax */
	and ecx, HEX(7fffffff)			/* Mask out invalid field in the mantissa */

	shr eax, 23					/* Shift the exponent in eax in place */
	or ecx, HEX(40000000)		/* Set bit for 1 in the mantissa */
	and eax, HEX(0ff)			/* Mask out invalid fields in the exponent in eax */

	xor ecx, edx				/* Make use of the sign bit expanded to full edx */

	sub eax, 125				/* Adjust exonent bias */

	sub ecx, edx				/* Substract -1 or add 1 if sign was set */

	mov edx, [esp + PARAM1]		/* Load pf into edx */
	mov [edx + lMant], ecx		/* Save back mantissa */
	mov [edx + lExp], eax		/* Save back exponent */

	pop ebp						/* Return */
	ret 8

SetFloat0:
	mov edx, [esp + PARAM1]		/* Load pf into edx */

	mov dword ptr [edx + lMant], 0	/* Set mantissa and exponent to 0 */
	mov dword ptr [edx + lExp], 0

	pop ebp						/* Return */
	ret 8


/*******************************************************************************
 * LONG
 * APIENTRY
 * FLOATOBJ_GetFloat(IN PFLOATOBJ pf);
 *
 */
_FLOATOBJ_GetFloat@4:
PUBLIC _FLOATOBJ_GetFloat@4
	push ebp
	mov ebp, esp

	mov edx, [esp + PARAM1]		/* Load pf into edx */
	mov eax, [edx + lMant]		/* Load mantissa into eax */
	mov ecx, [edx + lExp]		/* Load exponent into ecx */

	cdq							/* Calculate abs(mantissa) */
	xor eax, edx

	add ecx, 125

	sub eax, edx
	jz GetFloatRet

	and ecx, HEX(0ff)			/* Mask out invalid fields in the exponent */
	and eax, HEX(3fffffff)		/* Mask out invalid fields in mantissa */

	shl ecx, 23					/* Shift exponent in place */
	shr eax, 7					/* Shift mantissa in place */

	and edx, HEX(80000000)			/* Reduce edx to sign bit only */

	or eax, ecx					/* Set exponent in result */
	or eax, edx					/* Set sign bit in result */

GetFloatRet:
	/* Return */
	pop ebp
	ret 4



/******************************************************************************
 * VOID
 * APIENTRY
 * FLOATOBJ_SetLong(OUT PFLOATOBJ pf, IN LONG l);
 *
 * Instead of using abs(l), which is 3 + 2 instructions, use a branch.
 */
_FLOATOBJ_SetLong@8:
PUBLIC _FLOATOBJ_SetLong@8
	push ebp
	mov ebp, esp

	mov eax, [esp + PARAM2]		/* Load l into eax */
	mov edx, [esp + PARAM1]		/* Load pf into edx */

	test eax, eax				/* different handling for <0, =0 and >0 */
	js SetLongNeg
	jz SetLong0

	bsr ecx, eax				/* Get number of most significant bit aka log2(l) */
	mov [edx + lExp], ecx		/* Safe log2(l) into exponent */

	neg ecx						/* Calculate necessary shift */
	add ecx, 30

	add dword ptr [edx + lExp], 2	/* Adjust exponent */

	shl eax, cl					/* Shift mantissa in place */
	mov [edx + lMant], eax		/* Save mantissa */

	pop ebp						/* Return */
	ret 8

SetLongNeg:
	neg eax						/* Get absolute value of l */
	bsr ecx, eax				/* Get number of most significant bit aka log2(l) */
	neg eax						/* Back to negative */

	mov [edx + lExp], ecx		/* Safe log2(-l) into exponent */

	neg ecx						/* Calculate necessary shift */
	add ecx, 30

	add dword ptr [edx + lExp], 2	/* Adjust exponent */

	shl eax, cl					/* Shift mantissa in place */
	mov [edx + lMant], eax		/* Save mantissa */

	pop ebp						/* Return */
	ret 8

SetLong0:
	mov dword ptr [edx + lMant], 0	/* Set mantissa and exponent to 0 */
	mov dword ptr [edx + lExp], 0

	pop ebp						/* Return */
	ret 8


/*******************************************************************************
 * LONG
 * APIENTRY
 * FLOATOBJ_GetLong(IN PFLOATOBJ pf);
 *
 */
_FLOATOBJ_GetLong@4:
PUBLIC _FLOATOBJ_GetLong@4
	push ebp
	mov ebp, esp

	mov edx, [ebp + PARAM1]		/* Load pf into edx */
	mov ecx, 32					/* Load (32 - lExp) into ecx */
	sub ecx, [edx + lExp]
	jle short GetLong2			/* Check for Overflow */

	mov eax, [edx + lMant]		/* Load mantissa into eax */
	sar eax, cl					/* Signed shift mantissa according to exponent */

	pop ebp						/* Return */
	ret 4

GetLong2:
	xor eax, eax				/* Overflow, return 0 */
	pop ebp
	ret 4


/******************************************************************************
 * BOOL
 * APIENTRY
 * FLOATOBJ_Equal(IN PFLOATOBJ pf1, IN PFLOATOBJ pf2);
 */
_FLOATOBJ_Equal@8:
PUBLIC _FLOATOBJ_Equal@8
	push ebp
	mov ebp, esp

	mov ecx, [esp + PARAM1]		/* Load pf1 into ecx */
	mov eax, [esp + PARAM2]		/* Load pf2 into ecx */

	mov edx, [ecx + lExp]		/* Get float1 in ecx, edx */
	mov ecx, [ecx + lMant]

	sub edx, [eax + lExp]		/* Calculate diference to float2 */
	sub ecx, [eax + lMant]

	or edx, ecx					/* Combine */

	mov eax, 0					/* Set eax if combination is 0 */
	setz al

	pop ebp						/* Return */
	ret 8


/******************************************************************************
 * BOOL
 * APIENTRY
 * FLOATOBJ_EqualLong(IN PFLOATOBJ pf, IN LONG l);
 */
_FLOATOBJ_EqualLong@8:
PUBLIC _FLOATOBJ_EqualLong@8
	push ebp
	mov ebp, esp

	mov eax, [esp + PARAM1]		/* Load pf into eax */
	mov ecx, 32					/* Load (32 - lExp) into ecx */
	sub ecx, [eax + lExp]
	mov edx, [eax + lMant]		/* Load mantissa into edx */
	sar edx, cl					/* Signed shift mantissa according to exponent */
	shl edx, cl					/* Shift the mantissa back */
	cmp edx, [eax + lMant]		/* Check whether bits were killed by shifting */
	jnz EqualLongFalse			/* We have truncated the mantissa, return 0 */

	sar edx, cl					/* Shift the mantissa again */
	xor eax, eax				/* Set return value ... */
	cmp edx, [esp + PARAM2]		/* TRUE if shifted mantissa equals the LONG */
	setz al

	pop ebp						/* Return */
	ret 8

EqualLongFalse:
	xor eax, eax				/* Return FALSE */
	pop ebp
	ret 8


/******************************************************************************
 * BOOL
 * APIENTRY
 * FLOATOBJ_GreaterThan(IN PFLOATOBJ pf, IN PFLOATOBJ pf1);
 *
 */
_FLOATOBJ_GreaterThan@8:
PUBLIC _FLOATOBJ_GreaterThan@8
	push ebp
	mov ebp, esp

	mov eax, [ebp + PARAM1]		/* Load pointer to efloat1 in eax */
	mov edx, [ebp + PARAM2]		/* Load pointer to efloat2 in edx */

	mov ecx, [eax + lMant]		/* Load mantissa1 in ecx */
	mov edx, [edx + lMant]		/* Load mantissa2 in edx */

	sar ecx, 31					/* Calculate sign(lMant1) in ecx */
	sar edx, 31					/* Calculate sign(lMant2) in edx */

	cmp ecx, edx				/* Branch if both have the same sign */
	je GreaterThan_2

	/* Mantissae have different sign */
	mov eax, 0					/* Return (sign(lMant1) > sign(lMant2)) */
	setg al
	pop ebp
	ret 8

GreaterThan_2:
	/* Mantissae have the same sign */

	mov edx, [ebp + PARAM2]		/* Reload pointer to float2 in edx */
	test ecx, ecx				/* Branch if sign is negative */
	js GreaterThan_neg

	/* Both mantissae are positive or 0 */

	or ecx, [edx + lMant]		/* Branch if one mantissa is 0 */
	jz GreaterThan_pos2

	/* Both mantissae are positive */

	mov ecx, [eax + lExp]		/* Branch if exponents are equal */
	cmp ecx, [edx + lExp]
	je GreaterThan_pos2

	mov eax, 0					/* Return (lExp1 > lExp2) */
	setg al
	pop ebp
	ret 8

GreaterThan_pos2:
	/* Exponents are equal or one mantissa is 0 */

	mov ecx, [eax + lMant]		/* Return (lMant1 > lMant2) */
	cmp ecx, [edx + lMant]
	mov eax, 0
	setg al
	pop ebp
	ret 8

GreaterThan_neg:
	/* Both mantissae are negative */

	mov ecx, [eax + lExp]		/* Branch if exponents are equal */
	cmp ecx, [edx + lExp]
	je GreaterThan_neg2

	/* Both mantissae negative, exponents are different */

	mov eax, 0					/* Return (lExp1 < lExp2) */
	setl al
	pop ebp
	ret 8

GreaterThan_neg2:
	/* Both mantissae negative, exponents are equal */

	mov ecx, [eax + lMant]		/* Return (lMant1 < lMant2) */
	cmp ecx, [edx + lMant]
	mov eax, 0
	setl al
	pop ebp
	ret 8



/******************************************************************************
 * VOID
 * APIENTRY
 * FLOATOBJ_GreaterThanLong(IN OUT PFLOATOBJ pf, IN LONG l);
 *
 * Currently implemented as a wrapper around FLOATOBJ_SetLong and
 * LOATOBJ_GreaterThan
 */
_FLOATOBJ_GreaterThanLong@8:
PUBLIC _FLOATOBJ_GreaterThanLong@8
	push ebp
	mov ebp, esp

	sub esp, 8					/* Make room for a FLOATOBJ on the stack */
	mov eax, [ebp + PARAM2]		/* Load LONG into eax */

	lea ecx, [ebp -8]			/* Load pointer to local FLOATOBJ into ecx */

	push eax					/* Push LONG on the stack */
	push ecx					/* Push pointer to local FLOATOBJ on the stack */
	call _FLOATOBJ_SetLong@8	/* Set the local FLOATOBJ */

	lea ecx, [ebp -8]			/* Push pointer to the local FLOATOBJ on the stack */
	push ecx
	push [ebp + PARAM1]			/* Push the FLOATOBJ param on the stack */
	call _FLOATOBJ_GreaterThan@8	/* Compare */

	mov esp, ebp				/* Cleanup and return */
	pop ebp
	ret 8


/******************************************************************************
 * BOOL
 * APIENTRY
 * FLOATOBJ_LessThan(IN PFLOATOBJ pf, IN PFLOATOBJ pf1);
 *
 */
_FLOATOBJ_LessThan@8:
PUBLIC _FLOATOBJ_LessThan@8
	push ebp
	mov ebp, esp

	mov eax, [ebp + PARAM1]		/* Load pointer to floats in eax and edx */
	mov edx, [ebp + PARAM2]

	mov ecx, [eax + lMant]		/* Load mantissae in ecx and edx */
	mov edx, [edx + lMant]

	sar ecx, 31					/* Calculate sign(lMant1) and sign(lMant2) */
	sar edx, 31

	cmp ecx, edx				/* Branch if both have the same sign */
	je LessThan_2

	/* Mantissae have different sign */

	mov eax, 0					/* Return (sign(lMant1) < sign(lMant2)) */
	setl al
	pop ebp
	ret 8

LessThan_2:
	/* Mantissae have the same sign */


	mov edx, [ebp + PARAM2]		/* Reload pointer to float2 in edx */

	test ecx, ecx				/* Branch if sign is negative */
	js LessThan_neg

	/* Both mantissae are positive or 0 */

	or ecx, [edx + lMant]		/* Branch if one mantissa is 0 */
	jz LessThan_pos2

	/* Both mantissae are positive */

	mov ecx, [eax + lExp]		/* Branch if exponents are equal */
	cmp ecx, [edx + lExp]
	je LessThan_pos2

	mov eax, 0					/* Return (lExp1 < lExp2) */
	setl al
	pop ebp
	ret 8

LessThan_pos2:
	/* Exponents are equal or one mantissa is 0 */

	mov ecx, [eax + lMant]		/* Return (lMant1 < lMant2) */
	cmp ecx, [edx + lMant]
	mov eax, 0
	setl al
	pop ebp
	ret 8

LessThan_neg:
	/* Both mantissae are negative */

	mov ecx, [eax + lExp]		/* Branch if exponents are equal */
	cmp ecx, [edx + lExp]
	je LessThan_neg2

	/* Both mantissae negative, exponents are different */

	mov eax, 0					/* Return (lExp1 > lExp2) */
	setg al
	pop ebp
	ret 8

LessThan_neg2:
	/* Both mantissae negative, exponents are equal */

	mov ecx, [eax + lMant]		/* Return (lMant1 > lMant2) */
	cmp ecx, [edx + lMant]
	mov eax, 0
	setg al
	pop ebp
	ret 8


/******************************************************************************
 * VOID
 * APIENTRY
 * FLOATOBJ_LessThanLong(IN OUT PFLOATOBJ pf, IN LONG l);
 *
 * Currently implemented as a wrapper around FLOATOBJ_SetLong and FLOATOBJ_LessThan
 */
_FLOATOBJ_LessThanLong@8:
PUBLIC _FLOATOBJ_LessThanLong@8
	push ebp
	mov ebp, esp

	sub esp, 8					/* Make room for a FLOATOBJ on the stack */
	mov eax, [ebp + PARAM2]		/* Load LONG into eax */

	lea ecx, [ebp -8]			/* Load pointer to local FLOATOBJ into ecx */
	push eax					/* Push LONG on the stack */
	push ecx					/* Push pointer to local FLOATOBJ on the stack */
	call _FLOATOBJ_SetLong@8	/* Set the local FLOATOBJ */

	lea ecx, [ebp -8]			/* Push pointer to the local FLOATOBJ on the stack */
	push ecx
	push [ebp + PARAM1]			/* Push the FLOATOBJ param on the stack */
	call _FLOATOBJ_LessThan@8	/* Compare */

	mov esp, ebp				/* Cleanup and return */
	pop ebp
	ret 8



/******************************************************************************
 * VOID
 * APIENTRY
 * FLOATOBJ_Mul(IN OUT PFLOATOBJ pf1, IN PFLOATOBJ pf2);
 *
 *  (mant1 * 2^exp1) * (mant2 * 2^exp2) = (mant1 * mant2) * 2^(exp1 + exp2)
 *  or mant = mant1 * mant2 and exp = exp1 + exp2
 *  No special handling for 0, where mantissa is 0
 */
_FLOATOBJ_Mul@8:
PUBLIC _FLOATOBJ_Mul@8
	push ebp
	mov ebp, esp

	mov edx, [esp + PARAM1]		/* Load pf1 into edx */
	mov ecx, [esp + PARAM2]		/* Load pf2 into ecx */
	mov eax, [ecx + lMant]		/* Load mantissa2 into eax */
	mov ecx, [ecx + lExp]		/* Load exponent2 into ecx */

	imul dword ptr [edx + lMant]	/* Multiply eax with mantissa 1 */

	test edx, edx				/* Special handling for result < 0 */
	js MulNeg

	shl edx, 2					/* Get new mantissa from bits 30 to 62 */
	shr eax, 30					/* of edx:eax into edx */
	or eax, edx

	mov edx, ecx				/* Need ecx for the shift, safe exp2 to free edx */
	mov ecx, 0					/* Check for highest bit */
	sets cl
	shr eax, cl					/* Normalize mantissa in eax */

	jz Mul0						/* All 0? */

	lea edx, [edx + ecx -2]		/* Normalize exponent in edx */


	mov ecx, [esp + PARAM1]		/* Load pf1 into ecx */
	mov [ecx + lMant], eax		/* Save back mantissa */
	add [ecx + lExp], edx		/* Save back exponent */

	pop ebp						/* Return */
	ret 8

MulNeg:

	shl edx, 2					/* Get new mantissa from bits 30 to 62 */
	shr eax, 30					/* of edx:eax into edx */
	or eax, edx

	mov edx, ecx				/* Need ecx for the shift, safe exp2 to free edx */

	mov ecx, 0					/* Check for highest bit */
	setns cl
	shr eax, cl					/* Normalize mantissa in eax */

	jz Mul0						/* All 0? */


	lea edx, [edx + ecx -2]		/* Normalize exponent in edx */
	or eax, HEX(80000000)			/* Set sign bit */

	mov ecx, [esp + PARAM1]		/* Load pf1 into ecx */
	mov [ecx + lMant], eax		/* Save back mantissa */
	add [ecx + lExp], edx		/* Save back exponent */

	pop ebp						/* Return */
	ret 8

Mul0:
	mov ecx, [esp + PARAM1]		/* Load pf1 into ecx */
	mov [ecx + lMant], eax		/* Store 0 in mantissa */
	mov [ecx + lExp], eax		/* Store 0 in exponent */

	pop ebp						/* Return */
	ret 8


/******************************************************************************
 * VOID
 * APIENTRY
 * FLOATOBJ_MulFloat(IN OUT PFLOATOBJ pf, IN FLOATL f);
 *
 * Currently implemented as a wrapper around FLOATOBJ_SetFloat and FLOATOBJ_Mul
 */
_FLOATOBJ_MulFloat@8:
PUBLIC _FLOATOBJ_MulFloat@8
	push ebp
	mov ebp, esp

	sub esp, 8					/* Make room for a FLOATOBJ on the stack */
	mov eax, [ebp + PARAM2]		/* Load f into eax */
	lea ecx, [ebp -4]			/* Load pointer to local FLOATOBJ into ecx */
	push eax					/* Push f on the stack */
	push ecx					/* Push pointer to local FLOATOBJ on the stack */
	call _FLOATOBJ_SetFloat@8	/* Set the FLOATOBJ */

	lea ecx, [ebp -4]			/* Push pointer to local FLOATOBJ on the stack */
	push ecx
	push [ebp + PARAM1]			/* Push the FLOATOBJ param on the stack */
	call _FLOATOBJ_Mul@8		/* Multiply */

	mov esp, ebp				/* Cleanup and return */
	pop ebp
	ret 8


/******************************************************************************
 * VOID
 * APIENTRY
 * FLOATOBJ_MulLong(IN OUT PFLOATOBJ pf, IN LONG l);
 *
 * Currently implemented as a wrapper around FLOATOBJ_SetLong and FLOATOBJ_Mul
 */
_FLOATOBJ_MulLong@8:
PUBLIC _FLOATOBJ_MulLong@8
	push ebp
	mov ebp, esp

	sub esp, 8					/* Make room for a FLOATOBJ on the stack */
	mov eax, [ebp + PARAM2]		/* Load l into eax */
	lea ecx, [ebp -8]			/* Load pointer to local FLOATOBJ into ecx */
	push eax					/* Push l on the stack */
	push ecx					/* Push pointer to local FLOATOBJ on the stack */
	call _FLOATOBJ_SetLong@8	/* Set the local FLOATOBJ */

	lea ecx, [ebp -8]			/* Push pointer to local FLOATOBJ on the stack */
	push ecx
	push [ebp + PARAM1]			/* Push the FLOATOBJ param on the stack */
	call _FLOATOBJ_Mul@8		/* Multiply */

	mov esp, ebp				/* Cleanup and return */
	pop ebp
	ret 8


/*******************************************************************************
 * VOID
 * APIENTRY
 * FLOATOBJ_Div(IN OUT PFLOATOBJ pf1, IN PFLOATOBJ pf2);
 *
 */
_FLOATOBJ_Div@8:
PUBLIC _FLOATOBJ_Div@8
	push ebp
	mov ebp, esp
	push ebx

	mov eax, [ebp + PARAM2]		/* Load lMant2 into eax */
	mov eax, [eax + lMant]

	cdq							/* Calculate abs(lMant2) */
	xor eax, edx
	sub eax, edx
	jz DivError					/* Divide by zero error! */

	mov ebx, edx				/* Copy sign(lMant2) to ebx */
	mov ecx, eax				/* Copy abs(lMant2) to ecx */

	mov eax, [ebp + PARAM1]		/* Load lMant1 into eax */
	mov eax, [eax + lMant]

	cdq							/* Calculate abs(lMant1) */
	xor eax, edx
	sub eax, edx

	jz Div0						/* Dividend is 0? */

	xor ebx, edx				/* combine both signs in ebx */

	mov edx, eax				/* Prepare edx:eax for integer divide */
	xor eax, eax
	shr edx, 1
	div ecx						/* Do an unsigned divide */

	xor ecx, ecx				/* Adjust result */
	test eax, HEX(80000000)
	setnz cl
	shr eax, cl

	xor eax, ebx				/* Correct the result's sign */
	sub eax, ebx

	mov edx, [ebp + PARAM1]		/* Load pf1 into edx */
	mov [edx + lMant], eax		/* Safe back the mantissa */
	mov ebx, [ebp + PARAM2]		/* Load pf2 into ebx */
	sub ecx, [ebx + lExp]		/* Calculate exponent offset */
	inc ecx
	add [edx + lExp], ecx		/* Safe back exponent */

	pop ebx						/* Return */
	pop ebp
	ret 8

DivError:
Div0:
	mov edx, [ebp + PARAM1]		/* Load pf into edx */
	mov [edx + lMant], eax		/* Store 0 in mantissa */
	mov [edx + lExp], eax		/* Store 0 in exponent */

	pop ebx						/* Return */
	pop ebp
	ret 8


/******************************************************************************
 * VOID
 * APIENTRY
 * FLOATOBJ_DivFloat(IN OUT PFLOATOBJ pf, IN FLOATL f);
 *
 * Currently implemented as a wrapper around FLOATOBJ_SetFloat and FLOATOBJ_Div
 */
_FLOATOBJ_DivFloat@8:
PUBLIC _FLOATOBJ_DivFloat@8
	push ebp
	mov ebp, esp
	sub esp, 8					/* Make room for a FLOATOBJ on the stack */

	mov eax, [ebp + PARAM2]		/* Load f into eax */
	lea ecx, [ebp -4]			/* Load pointer to local FLOATOBJ into ecx */
	push eax					/* Push f on the stack */
	push ecx					/* Push pointer to local FLOATOBJ on the stack */
	call _FLOATOBJ_SetFloat@8	/* Set the FLOATOBJ */

	lea ecx, [ebp -4]			/* Push pointer to local FLOATOBJ on the stack */
	push ecx
	push [ebp + PARAM1]			/* Push the FLOATOBJ param on the stack */
	call _FLOATOBJ_Div@8		/* Divide */

	mov esp, ebp				/* Cleanup and return */
	pop ebp
	ret 8


/******************************************************************************
 * VOID
 * APIENTRY
 * FLOATOBJ_DivLong(IN OUT PFLOATOBJ pf, IN LONG l);
 *
 * Currently implemented as a wrapper around FLOATOBJ_SetLong and FLOATOBJ_Div
 */
_FLOATOBJ_DivLong@8:
PUBLIC _FLOATOBJ_DivLong@8
	push ebp
	mov ebp, esp
	sub esp, 8					/* Make room for a FLOATOBJ on the stack */

	mov eax, [ebp + PARAM2]		/* Load l into eax */
	lea ecx, [ebp -8]			/* Load pointer to local FLOATOBJ into ecx */
	push eax					/* Push l on the stack */
	push ecx					/* Push pointer to local FLOATOBJ on the stack */
	call _FLOATOBJ_SetLong@8	/* Set the local FLOATOBJ */

	lea ecx, [ebp -8]			/* Push pointer to the local FLOATOBJ on the stack */
	push ecx
	push [ebp + PARAM1]			/* Push the FLOATOBJ param on the stack */
	call _FLOATOBJ_Div@8		/* Divide */

	mov esp, ebp				/* Cleanup and return */
	pop ebp
	ret 8


/*******************************************************************************
 * VOID
 * APIENTRY
 * FLOATOBJ_Add(IN OUT PFLOATOBJ pf1, IN PFLOATOBJ pf2);
 *
 */
_FLOATOBJ_Add@8:
PUBLIC _FLOATOBJ_Add@8
	push ebp
	mov ebp, esp
	push ebx

	mov eax, [ebp + PARAM1]		/* Load pointer to pf1 in eax */
	mov ebx, [ebp + PARAM2]		/* Load pointer to pf2 in ebx */

	mov ecx, [eax + lExp]		/* Load float1 in (eax,ecx) */
	mov edx, [ebx + lExp]
	mov eax, [eax + lMant]		/* Load float2 in (ebx,edx) */
	mov ebx, [ebx + lMant]

	cmp ecx, edx				/* Check which one has the bigger lExp */
	jl Add2

	sub ecx, edx				/* Calculate lExp1 - lExp2 */
	sar eax, 1					/* Shift both mantissae 1 bit right */
	sar ebx, 1
	sar ebx, cl					/* Shift lMant2 according to exponent difference */

	add eax, ebx				/* Add the manrissae */
	jz AddIs0

	cdq							/* Calculate abs(mantissa) */
	xor eax, edx
	sub eax, edx

	bsr ecx, eax				/* Find most significant bit */
	neg ecx						/* and calculate needed normalize shift */
	add ecx, 30
	shl eax, cl
	dec ecx

	xor eax, edx				/* Go back to original sign */
	sub eax, edx

	mov edx, [ebp + PARAM1]		/* Reload pointer to float1 */

	pop ebx

	mov dword ptr [edx + lMant], eax	/* Safe mantissa */
	sub [edx + lExp], ecx		/* Adjust exponent */

	pop ebp						/* Return */
	ret 8

Add2:
	sub edx, ecx				/* Calculate lExp2 - lExp1 and put it into ecx */
	mov ecx, edx

	sar ebx, 1					/* Shift both mantissae 1 bit right */
	sar eax, 1
	sar eax, cl					/* Shift lMant2 according to exponent difference */

	add eax, ebx				/* Add the manrissae */
	jz AddIs0

	mov ebx, [ebp + PARAM1]		/* Reload pointer to float1 */
	add [ebx + lExp], ecx		/* Adjust exponent part 1 */

	cdq							/* Calculate abs(mantissa) */
	xor eax, edx
	sub eax, edx

	bsr ecx, eax				/* Find most significant bit */
	neg ecx						/* and calculate needed normalize shift */
	add ecx, 30
	shl eax, cl
	dec ecx

	xor eax, edx				/* Go back to original sign */
	sub eax, edx

	mov dword ptr [ebx + lMant], eax	/* Safe mantissa and adjust exponent */
	sub [ebx + lExp], ecx

	pop ebx						/* Return */
	pop ebp
	ret 8

AddIs0:
	/* Mantissa is 0, so float to (0,0) */
	mov eax, [ebp + PARAM1]
	pop ebx
	mov dword ptr [eax + lMant], 0
	mov dword ptr [eax + lExp], 0
	pop ebp
	ret 8


/******************************************************************************
 * VOID
 * APIENTRY
 * FLOATOBJ_AddFloat(IN OUT PFLOATOBJ pf, IN FLOATL f);
 *
 * Currently implemented as a wrapper around FLOATOBJ_SetFloat and FLOATOBJ_Add
 */
_FLOATOBJ_AddFloat@8:
PUBLIC _FLOATOBJ_AddFloat@8
	push ebp
	mov ebp, esp
	sub esp, 8					/* Make room for a FLOATOBJ on the stack */

	mov eax, [ebp + PARAM2]		/* Load f into eax */
	lea ecx, [ebp -4]			/* Load pointer to local FLOATOBJ into ecx */
	push eax					/* Push f on the stack */
	push ecx					/* Push pointer to local FLOATOBJ on the stack */
	call _FLOATOBJ_SetFloat@8	/* Set the FLOATOBJ */

	lea ecx, [ebp -4]			/* Push pointer to local FLOATOBJ on the stack */
	push ecx
	push [ebp + PARAM1]			/* Push the FLOATOBJ param on the stack */
	call _FLOATOBJ_Add@8		/* Add */

	mov esp, ebp				/* Cleanup and return */
	pop ebp
	ret 8


/******************************************************************************
 * VOID
 * APIENTRY
 * FLOATOBJ_AddLong(IN OUT PFLOATOBJ pf, IN LONG l);
 *
 * Currently implemented as a wrapper around FLOATOBJ_SetLong and FLOATOBJ_Add
 */
_FLOATOBJ_AddLong@8:
PUBLIC _FLOATOBJ_AddLong@8
	push ebp
	mov ebp, esp
	sub esp, 8					/* Make room for a FLOATOBJ on the stack */

	mov eax, [ebp + PARAM2]		/* Load l into eax */
	lea ecx, [ebp -8]			/* Load pointer to local FLOATOBJ into ecx */
	push eax					/* Push l on the stack */
	push ecx					/* Push pointer to local FLOATOBJ on the stack */
	call _FLOATOBJ_SetLong@8	/* Set the local FLOATOBJ */

	lea ecx, [ebp -8]			/* Push pointer to the local FLOATOBJ on the stack */
	push ecx
	push [ebp + PARAM1]			/* Push the FLOATOBJ param on the stack */
	call _FLOATOBJ_Add@8		/* Add */

	mov esp, ebp				/* Cleanup and return */
	pop ebp
	ret 8


/*******************************************************************************
 * VOID
 * APIENTRY
 * FLOATOBJ_Sub(IN OUT PFLOATOBJ pf, IN PFLOATOBJ pf1);
 *
 */
_FLOATOBJ_Sub@8:
PUBLIC _FLOATOBJ_Sub@8
	push ebp
	mov ebp, esp
	push ebx

	mov eax, [ebp + PARAM1]		/* Load pointer to floats in eax and ebx */
	mov ebx, [ebp + PARAM2]

	mov ecx, [eax + lExp]		/* Load float1 in (eax,ecx) and float2 in (ebx,edx) */
	mov edx, [ebx + lExp]
	mov eax, [eax + lMant]
	mov ebx, [ebx + lMant]

	cmp ecx, edx				/* Check which one has the bigger lExp */
	jl Sub2

	sub ecx, edx				/* Calculate lExp1 - lExp2 */
	sar eax, 1					/* Shift both mantissae 1 bit right */
	sar ebx, 1
	sar ebx, cl					/* Shift lMant2 according to exponent difference */

	sub eax, ebx				/* Substract the manrissae */
	jz SubIs0

	cdq							/* Calculate abs(mantissa) */
	xor eax, edx
	sub eax, edx

	bsr ecx, eax				/* Find most significant bit */
	neg ecx						/* and calculate needed normalize shift */
	add ecx, 30
	shl eax, cl
	dec ecx

	xor eax, edx				/* Go back to original sign */
	sub eax, edx

	mov edx, [ebp + PARAM1]		/* Reload pointer to float1 */

	pop ebx

	mov dword ptr [edx + lMant], eax /* Safe mantissa and adjust exponent */
	sub [edx + lExp], ecx

	pop ebp
	ret 8

Sub2:
	sub edx, ecx				/* Calculate lExp2 - lExp1 and put it into ecx */
	mov ecx, edx

	sar ebx, 1					/* Shift both mantissae 1 bit right */
	sar eax, 1
	sar eax, cl					/* Shift lMant2 according to exponent difference */

	sub eax, ebx				/* Substract the manrissae */
	jz AddIs0

	mov ebx, [ebp + PARAM1]		/* Reload pointer to float1 */
	add [ebx + lExp], ecx		/* Adjust exponent part 1 */

	cdq							/* Calculate abs(mantissa) */
	xor eax, edx
	sub eax, edx

	bsr ecx, eax				/* Find most significant bit */
	neg ecx						/* and calculate needed normalize shift */
	add ecx, 30
	shl eax, cl
	dec ecx

	xor eax, edx				/* Go back to original sign */
	sub eax, edx

	mov dword ptr [ebx + lMant], eax	/* Safe mantissa */
	sub [ebx + lExp], ecx		/* Adjust exponent */

	pop ebx						/* Return */
	pop ebp
	ret 8

SubIs0:
	/* Mantissa is 0, so float to (0,0) */
	mov eax, [ebp + PARAM1]
	pop ebx
	mov dword ptr [eax + lMant], 0
	mov dword ptr [eax + lExp], 0
	pop ebp
	ret 8

/******************************************************************************
 * VOID
 * APIENTRY
 * FLOATOBJ_SubFloat(IN OUT PFLOATOBJ pf, IN FLOATL f);
 *
 * Currently implemented as a wrapper around FLOATOBJ_SetFloat and FLOATOBJ_Sub
 */
_FLOATOBJ_SubFloat@8:
PUBLIC _FLOATOBJ_SubFloat@8
	push ebp
	mov ebp, esp
	sub esp, 8					/* Make room for a FLOATOBJ on the stack */

	mov eax, [ebp + PARAM2]		/* Load f into eax */
	lea ecx, [ebp -4]			/* Load pointer to local FLOATOBJ into ecx */
	push eax					/* Push f on the stack */
	push ecx					/* Push pointer to local FLOATOBJ on the stack */
	call _FLOATOBJ_SetFloat@8	/* Set the FLOATOBJ */

	lea ecx, [ebp -4]			/* Push pointer to local FLOATOBJ on the stack */
	push ecx
	push [ebp + PARAM1]			/* Push the FLOATOBJ param on the stack */
	call _FLOATOBJ_Sub@8		/* Substract */

	mov esp, ebp				/* Cleanup and return */
	pop ebp
	ret 8


/******************************************************************************
 * VOID
 * APIENTRY
 * FLOATOBJ_SubLong(IN OUT PFLOATOBJ pf, IN LONG l);
 *
 * Currently implemented as a wrapper around FLOATOBJ_SetLong and FLOATOBJ_Sub
 */
_FLOATOBJ_SubLong@8:
PUBLIC _FLOATOBJ_SubLong@8
	push ebp
	mov ebp, esp
	sub esp, 8					/* Make room for a FLOATOBJ on the stack */

	mov eax, [ebp + PARAM2]		/* Load l into eax */
	lea ecx, [ebp -8]			/* Load pointer to local FLOATOBJ into ecx */
	push eax					/* Push l on the stack */
	push ecx					/* Push pointer to local FLOATOBJ on the stack */
	call _FLOATOBJ_SetLong@8	/* Set the local FLOATOBJ */

	lea ecx, [ebp -8]			/* Push pointer to the local FLOATOBJ on the stack */
	push ecx
	push [ebp + PARAM1]			/* Push the FLOATOBJ param on the stack */
	call _FLOATOBJ_Sub@8		/* Substract */

	mov esp, ebp				/* Cleanup and return */
	pop ebp
	ret 8


/*******************************************************************************
 * VOID
 * APIENTRY
 * FLOATOBJ_Neg(IN OUT PFLOATOBJ pf);
 *
 */
_FLOATOBJ_Neg@4:
PUBLIC _FLOATOBJ_Neg@4
	push ebp
	mov ebp, esp

	mov ecx, [esp + PARAM1]		/* Load pf into ecx */
	neg dword ptr [ecx + lMant]	/* Negate lMant1 */

	pop ebp						/* Return */
	ret 4

END
/* EOF */
